package org.charles.zhifou.controller;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.Min;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.charles.zhifou.common.annotation.AuthCheck;
import org.charles.zhifou.common.exception.BusinessException;
import org.charles.zhifou.common.exception.ThrowUtils;
import org.charles.zhifou.common.response.BaseResponse;
import org.charles.zhifou.common.response.ResponseCodeEnum;
import org.charles.zhifou.common.response.ResponseUtils;
import org.charles.zhifou.common.utils.SqlUtils;
import org.charles.zhifou.enums.*;
import org.charles.zhifou.model.dto.app.*;
import org.charles.zhifou.model.entity.App;
import org.charles.zhifou.model.entity.User;
import org.charles.zhifou.model.vo.AppVO;
import org.charles.zhifou.model.vo.UserVO;
import org.charles.zhifou.service.AppService;
import org.charles.zhifou.service.UserService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.Date;

/**
 * <h1>应用接口</h1>
 *
 * @author charles
 * @version 1.0
 */
@RestController
@RequestMapping("/app")
@Slf4j
@Tag(name = "应用接口")
public class AppController {

    @Resource
    private AppService appService;

    @Resource
    private UserService userService;

    // region 增删改查

    /**
     * 创建应用
     *
     * @param appAddRequest 应用创建请求
     * @return 创建成功的应用 id
     */
    @PostMapping("/add")
    @Operation(summary = "创建应用")
    public BaseResponse<Long> addApp(@Validated @RequestBody AppAddRequest appAddRequest) {
        // 得分类应用不可使用 AI 评分
        if (appAddRequest.getScoringStrategy() == ScoringStrategyEnum.AI && appAddRequest.getAppType() == AppTypeEnum.SCORE) {
            throw new BusinessException(ResponseCodeEnum.PARAMS_ERROR, "得分类应用不可使用 AI 评分");
        }

        // 封装 App
        App app = new App();
        app.setId(null);
        app.setAppName(appAddRequest.getAppName());
        app.setAppDesc(appAddRequest.getAppDesc());
        app.setAppIcon(appAddRequest.getAppIcon());
        app.setAppType(appAddRequest.getAppType());
        app.setScoringStrategy(appAddRequest.getScoringStrategy());
        app.setReviewStatus(ReviewStatusEnum.REVIEWING);
        app.setReviewMessage(null);
        app.setReviewerId(null);
        app.setReviewTime(null);
        app.setUserId(userService.getLoginUser().getId());
                
        // 创建应用, 并返回新创建的应用 id
        boolean isSuccessful = appService.saveOrUpdate(app);
        ThrowUtils.throwIf(!isSuccessful, ResponseCodeEnum.OPERATION_ERROR, "数据库操作失败");

        return ResponseUtils.success(app.getId());
    }

    /**
     * 删除应用
     *
     * @param id 应用 id
     * @return 是否删除成功
     */
    @DeleteMapping("/delete")
    @Operation(summary = "删除应用")
    public BaseResponse<Boolean> deleteApp(
            @Min(value = 1, message = "id 必须大于 0")
            Long id
    ) {
        boolean isSuccessful = appService.deleteAppById(id);
        return ResponseUtils.success(isSuccessful);
    }

    /**
     * 更新应用 (仅管理员)
     *
     * @param appUpdateRequest 应用更新请求
     * @return 是否成功更新
     */
    @PostMapping("/update")
    @AuthCheck(neededRole = UserRoleEnum.ADMIN)
    @Operation(summary = "更新应用 (仅管理员)")
    public BaseResponse<Boolean> updateAppById(@Validated @RequestBody AppUpdateRequest appUpdateRequest) {
        // 得分类应用不可使用 AI 评分
        if (appUpdateRequest.getScoringStrategy() == ScoringStrategyEnum.AI && appUpdateRequest.getAppType() == AppTypeEnum.SCORE) {
            throw new BusinessException(ResponseCodeEnum.PARAMS_ERROR, "得分类应用不可使用 AI 评分");
        }

        App app = new App();
        app.setId(appUpdateRequest.getId());
        app.setAppName(appUpdateRequest.getAppName());
        app.setAppDesc(appUpdateRequest.getAppDesc());
        app.setAppIcon(appUpdateRequest.getAppIcon());
        app.setAppType(appUpdateRequest.getAppType());
        app.setScoringStrategy(appUpdateRequest.getScoringStrategy());
        app.setReviewStatus(appUpdateRequest.getReviewStatus());
        app.setReviewMessage(appUpdateRequest.getReviewMessage());
        app.setReviewerId(appUpdateRequest.getReviewerId());
        app.setReviewTime(appUpdateRequest.getReviewTime());
        app.setUserId(null);

        // 操作数据库
        Boolean isSuccessful = appService.updateById(app);
        return ResponseUtils.success(isSuccessful);
    }

    /**
     * 根据 id 获取应用 VO
     *
     * @param id 应用 id
     * @return 应用 VO
     */
    @GetMapping("/get_vo")
    @Operation(summary = "根据 id 获取应用 VO")
    public BaseResponse<AppVO> getAppVOById(
            @Min(value = 1, message = "id 必须大于 0")
            Long id
    ) {
        // 尝试获取, 获取不到就抛异常
        App app = appService.getById(id);
        ThrowUtils.throwIf(app == null, ResponseCodeEnum.NOT_FOUND_ERROR);

        // 这里需要额外补充 UserVo user 属性
        AppVO appVO = AppVO.entityToVo(app);
        User user = userService.getById(app.getUserId());
        UserVO userVo = UserVO.entityToVo(user);
        appVO.setUser(userVo);

        return ResponseUtils.success(appVO);
    }

    /**
     * 分页获取应用列表 (仅管理员)
     *
     * @param appQueryRequest 应用查询请求
     * @return 分页应用列表
     */
    @PostMapping("/list/page")
    @AuthCheck(neededRole = UserRoleEnum.ADMIN)
    @Operation(summary = "分页获取应用列表 (仅管理员)")
    public BaseResponse<Page<App>> listAppByPage(@Validated @RequestBody AppQueryRequest appQueryRequest) {
        // 获取分页参数
        long current = appQueryRequest.getCurrent();
        long size = appQueryRequest.getPageSize();

        // 查询数据库
        Page<App> appPage = appService.page(new Page<>(current, size), buildQueryWrapper(appQueryRequest));
        return ResponseUtils.success(appPage);
    }

    /**
     * 分页获取应用列表 VO
     *
     * @param appQueryRequest 应用查询请求
     * @return 分页应用 VO 列表
     */
    @PostMapping("/list/page_vo")
    @Operation(summary = "分页获取应用列表 VO")
    public BaseResponse<IPage<AppVO>> listAppVOByPage(@Validated @RequestBody AppQueryRequest appQueryRequest) {
        // 获取分页参数
        long current = appQueryRequest.getCurrent();
        long size = appQueryRequest.getPageSize();

        // 限制只能看到已过审的应用
        appQueryRequest.setReviewStatus(ReviewStatusEnum.PASSED);
        // 将排序字段改为蛇形命名
        appQueryRequest.setSortField(StrUtil.toUnderlineCase(appQueryRequest.getSortField()));

        // 查询数据库
        Page<AppVO> page = new Page<>(current, size);
        IPage<AppVO> appVOPage = appService.listAppVOByPage(page, appQueryRequest);
        return ResponseUtils.success(appVOPage);
    }

    /**
     * 分页获取当前登录用户创建的应用 VO 列表
     *
     * @param appQueryRequest 应用查询请求
     * @return 当前登录用户创建的应用列表
     */
    @PostMapping("my/list/page_vo")
    @Operation(summary = "分页获取当前登录用户创建的应用 VO 列表")
    public BaseResponse<IPage<AppVO>> listMyAppVOByPage(@Validated @RequestBody AppQueryRequest appQueryRequest) {
        // 获取分页参数
        long current = appQueryRequest.getCurrent();
        long size = appQueryRequest.getPageSize();

        // 限制查询当前用户的应用
        appQueryRequest.setUserId(userService.getLoginUser().getId());
        // 将排序字段改为蛇形命名
        appQueryRequest.setSortField(StrUtil.toUnderlineCase(appQueryRequest.getSortField()));

        // 查询数据库
        Page<AppVO> page = new Page<>(current, size);
        IPage<AppVO> appVOPage = appService.listAppVOByPage(page, appQueryRequest);

        return ResponseUtils.success(appVOPage);
    }

    /**
     * 编辑应用
     *
     * @param appEditRequest 编辑应用请求
     * @return 是否编辑成功
     */
    @PostMapping("/edit")
    @Operation(summary = "编辑应用")
    public BaseResponse<Boolean> editApp(@Validated @RequestBody AppEditRequest appEditRequest) {
        // 得分类应用不可使用 AI 评分
        if (appEditRequest.getScoringStrategy() == ScoringStrategyEnum.AI && appEditRequest.getAppType() == AppTypeEnum.SCORE) {
            throw new BusinessException(ResponseCodeEnum.PARAMS_ERROR, "得分类应用不可使用 AI 评分");
        }

        // 封装参数 (需要重置审核状态)
        App app = new App();
        app.setId(appEditRequest.getId());
        app.setAppName(appEditRequest.getAppName());
        app.setAppDesc(appEditRequest.getAppDesc());
        app.setAppIcon(appEditRequest.getAppIcon());
        app.setAppType(appEditRequest.getAppType());
        app.setScoringStrategy(appEditRequest.getScoringStrategy());
        app.setReviewStatus(ReviewStatusEnum.REVIEWING);
        app.setReviewMessage(null);
        app.setReviewerId(null);
        app.setReviewTime(null);

        // 执行更新
        boolean isSuccessful = appService.editAppById(app);
        return ResponseUtils.success(isSuccessful);
    }

    // endregion

    /**
     * 应用审核 (仅管理员)
     *
     * @param reviewRequest 审核请求
     * @return 是否审核成功
     */
    @PostMapping("/review")
    @AuthCheck(neededRole = UserRoleEnum.ADMIN)
    @Operation(summary = "应用审核 (仅管理员)")
    public BaseResponse<Boolean> doAppReview(@Validated @RequestBody AppReviewRequest reviewRequest) {
        // 封装参数
        App app = new App();
        app.setId(reviewRequest.getId());
        app.setAppName(null);
        app.setAppDesc(null);
        app.setAppIcon(null);
        app.setAppType(null);
        app.setScoringStrategy(null);
        app.setReviewStatus(reviewRequest.getReviewStatus());
        app.setReviewMessage(reviewRequest.getReviewMessage());
        app.setReviewerId(userService.getLoginUser().getId());
        app.setReviewTime(new Date());
        app.setUserId(null);

        // 执行更新
        boolean isSuccessful = appService.reviewAppById(app);
        return ResponseUtils.success(isSuccessful);
    }

    public static QueryWrapper<App> buildQueryWrapper(AppQueryRequest appQueryRequest) {
        QueryWrapper<App> queryWrapper = new QueryWrapper<>();
        if (appQueryRequest == null) {
            return queryWrapper;
        }

        Long id = appQueryRequest.getId();
        String appName = appQueryRequest.getAppName();
        String appDesc = appQueryRequest.getAppDesc();
        String appIcon = appQueryRequest.getAppIcon();
        AppTypeEnum appType = appQueryRequest.getAppType();
        ScoringStrategyEnum scoringStrategy = appQueryRequest.getScoringStrategy();
        ReviewStatusEnum reviewStatus = appQueryRequest.getReviewStatus();
        String reviewMessage = appQueryRequest.getReviewMessage();
        Long reviewerId = appQueryRequest.getReviewerId();
        Long userId = appQueryRequest.getUserId();
        Long notId = appQueryRequest.getNotId();
        String searchText = appQueryRequest.getSearchText();
        String sortField = StrUtil.toUnderlineCase(appQueryRequest.getSortField());
        SqlSortOrderEnum sortOrder = appQueryRequest.getSortOrder();


        // 补充需要的查询条件
        // 从多字段中搜索
        if (StringUtils.isNotBlank(searchText)) {
            // 需要拼接查询条件
            queryWrapper.and(qw -> qw.like("app_name", searchText).or().like("app_desc", searchText));
        }
        // 模糊查询
        queryWrapper.like(StringUtils.isNotBlank(appName), "app_name", appName);
        queryWrapper.like(StringUtils.isNotBlank(appDesc), "app_desc", appDesc);
        queryWrapper.like(StringUtils.isNotBlank(reviewMessage), "review_message", reviewMessage);
        // 精确查询
        queryWrapper.eq(StringUtils.isNotBlank(appIcon), "app_icon", appIcon);
        queryWrapper.ne(ObjectUtils.isNotEmpty(notId), "id", notId);
        queryWrapper.eq(ObjectUtils.isNotEmpty(id), "id", id);
        queryWrapper.eq(ObjectUtils.isNotEmpty(appType), "app_type", appType);
        queryWrapper.eq(ObjectUtils.isNotEmpty(scoringStrategy), "scoring_strategy", scoringStrategy);
        queryWrapper.eq(ObjectUtils.isNotEmpty(reviewStatus), "review_status", reviewStatus);
        queryWrapper.eq(ObjectUtils.isNotEmpty(reviewerId), "reviewer_id", reviewerId);
        queryWrapper.eq(ObjectUtils.isNotEmpty(userId), "user_id", userId);
        // 排序规则
        queryWrapper.orderBy(SqlUtils.validSortField(sortField), !SqlSortOrderEnum.DESC.equals(sortOrder), sortField);

        return queryWrapper;
    }
}
